package main

import (
	"log"
	"math/rand"
	"sync"
	"time"
)

/*
一个生产者多个消费者，但是退出操作不是生产者执行，而是第三方 goroutine
*/
func main() {
	rand.Seed(time.Now().UnixNano())
	log.SetFlags(0)

	const Max = 100000
	const NumReceivers = 100

	const NumThirdParties = 15

	wgReceivers := sync.WaitGroup{}
	wgReceivers.Add(NumReceivers)

	dataCh := make(chan int)
	closing := make(chan struct{})
	closed := make(chan struct{})

	stop := func() { // 此函数第一次被执行会先往 closing channel 发送值
		select {
		case closing <- struct{}{}:
			<-closed
		case <-closed:
		}

		// 都会堵塞 直到从 closed 拿出数据：close channel 被关闭，则不会被堵塞
		// 生产者的 deferred 函数执行后，第三方 groutine 都会接收到信号退出
	}

	for i := 0; i < NumThirdParties; i++ {
		go func() {
			r := 1 + rand.Intn(3)
			time.Sleep(time.Duration(r) * time.Second)
			stop()
		}()
	}
	// 生产者
	go func() {
		defer func() {
			close(closed)
			close(dataCh)
		}()
		for {
			select {
			case <-closing: // 如果被第三方 goroutine 通知退出
				return
			default:

			}

			select {
			case <-closing:
				return
			case dataCh <- rand.Intn(Max):
			}
		}
	}()

	for i := 0; i < NumReceivers; i++ {
		go func() {
			defer wgReceivers.Done() // 等待所有消费者退出

			for value := range dataCh {
				log.Println(value)
			}
		}()
	}
	wgReceivers.Wait()

}
